package com.terra.ns.imp.common.mybatis.mapper

import cn.hutool.core.collection.ListUtil
import com.baomidou.mybatisplus.annotation.TableField
import com.baomidou.mybatisplus.core.conditions.Wrapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper
import com.baomidou.mybatisplus.core.toolkit.Constants
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.terra.ns.imp.common.vo.request.PageParam
import com.terra.ns.imp.common.vo.response.PageResult
import org.apache.ibatis.annotations.Param
import java.lang.reflect.Field
import kotlin.reflect.KProperty

/**
@author qins
@date 2023/5/31
@desc mybatis plus增加一些通用方法
 在接口层方法有body，使用的是Java 接口默认实现
 */
interface BaseMapperX<T> : BaseMapper<T> {

    fun selectOneByField(clazz: Class<*>, column: KProperty<*>, value: Any) : T? {
        return selectOne(KtQueryWrapperX(clazz).eqX(column, value).lastLimit1() as Wrapper<T>)
    }

    fun selectListByField(clazz: Class<*>, column: KProperty<*>, value: Any) : List<T> {
        return selectList(KtQueryWrapper(clazz).eq(column, value) as Wrapper<T>)
    }

    fun selectListInField(clazz: Class<*>, column: KProperty<*>, value: List<Any>) : List<T> {
        if(value.isEmpty()) return emptyList()
        return selectList(KtQueryWrapper(clazz).`in`(column, value) as Wrapper<T>)
    }

    fun updateByField(entity: T, column: KProperty<*>, value: Any) {
        update(entity, KtUpdateWrapper(entity!!::class.java).eq(column, value) as Wrapper<T>)
    }

    fun deleteByField(clazz: Class<*>, column: KProperty<*>, value: Any) {
        delete(KtQueryWrapper(clazz).eq(column, value) as Wrapper<T>)
    }

    /**
     * 批量插入方法，分割列表
     */
    fun batchInsertByBatchSize(entityList: List<T>, batchSize: Int = 100) {
        if(entityList.isEmpty()) return
        ListUtil.partition(entityList, batchSize).forEach {
            this.insertBatchSomeColumn(it)
        }
    }

    /**
     * 批量插入方法，未分批次处理，有sql超长风险
     */
    fun insertBatchSomeColumn(entityList: Collection<T>)

    /**
     * 更新所有属性包含为null的值
     * 基础忽略字段有 主键：id, 逻辑删除：deleted, 自动填充：createDate,modifyDate,createUser,modifyUser
     * @param entity 更新的新实体
     * @param updateWrapper 条件
     * @param ignoreColumn 除了基础忽略字段，需要额外忽略的列
     */
    fun updateFieldIncludeNull(@Param(Constants.ENTITY) entity : T,
                               @Param(Constants.WRAPPER) updateWrapper: Wrapper<T>,
                               @Param(Constants.LIST) ignoreColumn: List<String> = emptyList()) : Int

    /**
     * 判断exist=false 表示不是数据库字段
     */
    private fun isExistField(field: Field): Boolean {
        val tableFieldAnnotation = field.annotations.firstOrNull { it.annotationClass == TableField::class }
        return if(tableFieldAnnotation == null) true else (tableFieldAnnotation as TableField).exist
    }

    /**
     * 获取逆序排序后的第一条
     */
    fun queryLastOneByFieldOrderByDescField(clazz: Class<*>, column: KProperty<*>, value: Any, orderDescColumn: KProperty<*>): T? {
        return selectOne(KtQueryWrapperX(clazz).eqX(column, value).orderByDescX(orderDescColumn).lastLimit1() as Wrapper<T>)
    }

    /**
     * 在Mapper层封装mybatis plus分页
     */
    fun selectPage(pageParam : PageParam<*>, @Param(Constants.WRAPPER) queryWrapper: Wrapper<T>) : PageResult<T> {
        val mpPage = Page<T>(pageParam.pageNo, pageParam.pageSize)
        selectPage(mpPage, queryWrapper)
        // 转换返回
        return PageResult(pageParam.pageNo, pageParam.pageSize, mpPage.total, mpPage.records)
    }
}
